Skip to content

Add picks variable selection to ae_oview module#331

Open
osenan wants to merge 27 commits intomainfrom
oriol_ae_oview_picks@main
Open

Add picks variable selection to ae_oview module#331
osenan wants to merge 27 commits intomainfrom
oriol_ae_oview_picks@main

Conversation

@osenan
Copy link

@osenan osenan commented Mar 12, 2026

Pull Request

This partially closes #330

I based my changes in this PR.

Please compare both modules with this example app (requires to have teal.picks installed, osprey)

library("teal")
library("teal.picks")
devtools::load_all()

data <- teal_data() %>%
  within({
    library(dplyr)
    ADSL <- teal.data::rADSL
    ADAE <- teal.data::rADAE
    .add_event_flags <- function(dat) {
      dat <- dat %>%
        mutate(
          TMPFL_SER = AESER == "Y",
          TMPFL_REL = AEREL == "Y",
          TMPFL_GR5 = AETOXGR == "5",
          AEREL1 = (AEREL == "Y" & ACTARM == "A: Drug X"),
          AEREL2 = (AEREL == "Y" & ACTARM == "B: Placebo")
        )
      labels <- c(
        "Serious AE", "Related AE", "Grade 5 AE",
        "AE related to A: Drug X", "AE related to B: Placebo"
      )
      cols <- c("TMPFL_SER", "TMPFL_REL", "TMPFL_GR5", "AEREL1", "AEREL2")
      for (i in seq_along(labels)) {
        attr(dat[[cols[i]]], "label") <- labels[i]
      }
      dat
    }
    ADAE <- .add_event_flags(ADAE)
  })

join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_g_ae_oview(
      label = "Common AE (picks)",
      flag_var_anl = teal.picks::picks(
        teal.picks::datasets("ADAE"),
        teal.picks::variables(
           choices = c("TMPFL_SER", "TMPFL_REL", "TMPFL_GR5", "AEREL1", "AEREL2"),
          selected = "TMPFL_SER"
        )
      ),
      arm_var = teal.picks::picks(
        teal.picks::datasets("ADSL"),
        teal.picks::variables(
          choices = teal.picks::is_categorical(min.len = 2),
          selected = "ACTARMCD"
        )
      ),
      plot_height = c(600, 200, 2000)
    ),
    # Default method (old) for comparison
    tm_g_ae_oview(
      label = "Common AE (default)",
      dataname = "ADAE",
      flag_var_anl = teal.transform::choices_selected(
        selected = "AEREL1",
        choices = teal.transform::variable_choices(
          data[["ADAE"]],
          c("TMPFL_SER", "TMPFL_REL", "TMPFL_GR5", "AEREL1", "AEREL2")
        )
      ),
      arm_var = teal.transform::choices_selected(
        selected = "ACTARMCD",
        choices = c("ACTARM", "ACTARMCD")
      ),
      plot_height = c(600, 200, 2000)
    )
  )
)

shinyApp(app$ui, app$server)

I refactored the tm_g_ae_oview module to create a generic, keep the default for teal.transform and add a method for picks variable selection. The module works as expected and setting the variables is better with picks. The issue reported in the similar PR on the plot dimensions is fixed if we set the plot dimensions in the module. The ui of the picks ui components is different and it breaks, in my opinion, the color pattern of the teal app.

image image

Here the teal.transform module

image image

I added simple tests for the module as well

@osenan osenan added the core label Mar 12, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2026


🎉 Thank you for your contribution! Before this PR can be accepted, we require that you read and agree to our Contributor License Agreement.
You can digitally sign the CLA by posting a comment on this Pull Request in the format shown below. This agreement will apply to this PR as well as all future contributions on this repository.


I have read the CLA Document and I hereby sign the CLA


osenan seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@osenan osenan requested a review from a team March 12, 2026 11:38
@osenan
Copy link
Author

osenan commented Mar 12, 2026

I have read the CLA Document and I hereby sign the CLA

@osenan osenan marked this pull request as draft March 12, 2026 14:59
@osenan
Copy link
Author

osenan commented Mar 12, 2026

Changed to draft as I need to fix:

  • Checks
  • Plot
  • Decorators

Copy link
Contributor

@averissimo averissimo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some preliminary comments.

  • I believe this is a good case for only keeping 1 version of the module logic. (We can convert directly from choices_selected -> variables())
  • I see that you're using picks(), consider using variables() instead for arm_var and flag_var_anl
    • And then create picks() inside the tm_g_ae_oview() call

Comment on lines +85 to +98
arm_var = teal.picks::picks(
teal.picks::datasets(),
teal.picks::variables(
choices = teal.picks::is_categorical(min.len = 2),
selected = 1L
)
),
flag_var_anl = teal.picks::picks(
teal.picks::datasets(),
teal.picks::variables(
choices = teal.picks::is_categorical(min.len = 2),
selected = 1L
)
),
Copy link
Contributor

@averissimo averissimo Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good candidate to use variables() in the arguments:

Suggested change
arm_var = teal.picks::picks(
teal.picks::datasets(),
teal.picks::variables(
choices = teal.picks::is_categorical(min.len = 2),
selected = 1L
)
),
flag_var_anl = teal.picks::picks(
teal.picks::datasets(),
teal.picks::variables(
choices = teal.picks::is_categorical(min.len = 2),
selected = 1L
)
),
arm_var = teal.picks::variables(
choices = teal.picks::is_categorical(min.len = 2),
selected = 1L
),
flag_var_anl = teal.picks::variables(
choices = teal.picks::is_categorical(min.len = 2),
selected = 1L
),

You can then overwrite arguments with picks() in tm_g_ae_oview.variables (and use dataname):

# ...
   arm_var <- teal.picks::picks(datasets(dataname), arm_var)
   flag_var_anl <- teal.picks::picks(datasets(dataname), flag_var_anl)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed, actually it is simpler good idea

Comment on lines +168 to +177
selectInput(
ns("arm_ref"),
"Control",
choices = NULL
),
selectInput(
ns("arm_trt"),
"Treatment",
choices = NULL
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting case here as we have dependent input fields from arm_var = picks(...).

Should these be created independently reusing arm_var datasets & variables

  • that is: having 2 picks
  • this will create problems downstream though

Or [possible feature]

Is this a case for having multiple values() in a picks, which generate multiple selectors.

picsk(datasets("ADAE"), variables(), values(), values()) # with some way to differentiate between control and treatement

@gogonzo maybe this is one of the cases of bookmark manager we remember.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is related to this issue: insightsengineering/teal.picks#14.
My initial plan was to go for the second option. But it is hard to distinguish here what is what: should picks(datasets("ADAE"), variables(), values(), values()) join all the values in a single selection or not? To disambiguate I thought about using operators: picks(datasets("ADAE"), variables()) + values() | values(): a picks with two options/selectors.

Currently I think it is better if we create a function to handle those cases.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's solve the issue and then update this module

osenan and others added 4 commits March 16, 2026 12:31
Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com>
Signed-off-by: Oriol Senan  <35930244+osenan@users.noreply.github.com>
Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com>
Signed-off-by: Oriol Senan  <35930244+osenan@users.noreply.github.com>
Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com>
Signed-off-by: Oriol Senan  <35930244+osenan@users.noreply.github.com>
Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com>
Signed-off-by: Oriol Senan  <35930244+osenan@users.noreply.github.com>
@osenan
Copy link
Author

osenan commented Mar 16, 2026

I have read the CLA Document and I hereby sign the CLA

@osenan osenan marked this pull request as ready for review March 17, 2026 06:45
@osenan
Copy link
Author

osenan commented Mar 17, 2026

The plot and decorator I will handle in a separate issue finally

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

badge

Code Coverage Summary

Filename                    Stmts    Miss  Cover    Missing
------------------------  -------  ------  -------  ---------------------
R/tm_g_ae_oview_picks.R       274     210  23.36%   80-84, 89-93, 162-397
R/tm_g_ae_oview.R              33       0  100.00%
R/tm_g_ae_sub.R               288     288  0.00%    60-379
R/tm_g_butterfly.R            371     371  0.00%    125-534
R/tm_g_decorate.R              42      42  0.00%    17-91
R/tm_g_events_term_id.R       271     271  0.00%    63-364
R/tm_g_heat_bygrade.R         293     293  0.00%    136-459
R/tm_g_patient_profile.R      691     691  0.00%    159-913
R/tm_g_spiderplot.R           322     322  0.00%    100-464
R/tm_g_swimlane.R             345     345  0.00%    127-525
R/tm_g_waterfall.R            429     429  0.00%    109-590
R/utils.R                      85      80  5.88%    31-73, 107-240
R/zzz.R                         3       3  0.00%    4-7
TOTAL                        3447    3345  2.96%

Diff against main

Filename                   Stmts    Miss  Cover
-----------------------  -------  ------  --------
R/tm_g_ae_oview_picks.R     +274    +210  +23.36%
R/tm_g_ae_oview.R           -192    -225  +100.00%
TOTAL                        +82     -15  +2.81%

Results for commit: 5f0cfc2

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

Unit Tests Summary

 1 files   2 suites   0s ⏱️
 8 tests  8 ✅ 0 💤 0 ❌
20 runs  20 ✅ 0 💤 0 ❌

Results for commit 5f0cfc2.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
tm_g_ae_oview 👶 $+0.12$ $+7$ $0$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
tm_g_ae_oview 👶 $+0.03$ tm_g_ae_oview_argument_verification_fails_when_arm_var_is_choices_selected_but_flag_var_anl_is_pick
tm_g_ae_oview 👶 $+0.02$ tm_g_ae_oview_argument_verification_fails_when_arm_var_is_pick_but_flag_var_anl_is_choices_selected
tm_g_ae_oview 👶 $+0.05$ tm_g_ae_oview_module_creation_creates_a_teal_module_using_choices_selected_default_method_
tm_g_ae_oview 👶 $+0.02$ tm_g_ae_oview_module_creation_creates_a_teal_module_using_picks_.pick_method_

Results for commit 8195974

♻️ This comment has been updated with latest results.

@osenan
Copy link
Author

osenan commented Mar 17, 2026

Now the example should be tested with this app:


library(teal)
devtools::load_all()
library(teal.picks)

data <- teal_data() %>%
   within({
     library(dplyr)
     ADSL <- rADSL
     ADAE <- rADAE
     .add_event_flags <- function(dat) {
       dat <- dat %>%
         mutate(
           TMPFL_SER = AESER == "Y",
           TMPFL_REL = AEREL == "Y",
           TMPFL_GR5 = AETOXGR == "5",
           AEREL1 = (AEREL == "Y" & ACTARM == "A: Drug X"),
           AEREL2 = (AEREL == "Y" & ACTARM == "B: Placebo")
         )
       labels <- c(
         "Serious AE", "Related AE", "Grade 5 AE",
         "AE related to A: Drug X", "AE related to B: Placebo"
       )
       cols <- c("TMPFL_SER", "TMPFL_REL", "TMPFL_GR5", "AEREL1", "AEREL2")
       for (i in seq_along(labels)) {
         attr(dat[[cols[i]]], "label") <- labels[i]
       }
       dat
     }
     ADAE <- .add_event_flags(ADAE)
   })

 join_keys(data) <- default_cdisc_join_keys[names(data)]

 ADAE <- data[["ADAE"]]

 app <- init(
   data = data,
   modules = modules(
     tm_g_ae_oview(
       label = "AE Overview",
       dataname = "ADAE",
       arm_var = teal.picks::variables(
          choices = tidyselect::starts_with("ACTARM"),
          selected = "ACTARMCD"
      ),
      flag_var_anl = teal.picks::variables(
          choices = c("TMPFL_SER", "TMPFL_REL", "TMPFL_GR5", "AEREL1", "AEREL2"),
          selected = "AEREL1"
      ),
      plot_height = c(600, 200, 2000)
     )
   )
 )
 if (interactive()) {
   shinyApp(app$ui, app$server)
 }

@osenan osenan requested a review from averissimo March 17, 2026 11:56
Copy link
Contributor

@averissimo averissimo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! It works great and it even supports picks conversion for choices_selected

@averissimo averissimo self-assigned this Mar 17, 2026
osenan and others added 6 commits March 17, 2026 15:31
Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com>
Signed-off-by: Oriol Senan  <35930244+osenan@users.noreply.github.com>
Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com>
Signed-off-by: Oriol Senan  <35930244+osenan@users.noreply.github.com>
@osenan osenan requested a review from averissimo March 18, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Allow modules to use teal.picks

3 participants